
package hk.ces.oxfam.patch.transaction;

import hk.ces.oxfam.patch.TransactionPatch;
import hk.ces.oxfam.patch.config.Config;
import hk.ces.oxfam.patch.obj.BeanPacker;
import hk.ces.oxfam.patch.obj.DataDict;
import hk.ces.oxfam.patch.obj.FieldInfo;
import hk.ces.oxfam.patch.obj.TableAndColumnBean;
import hk.ces.oxfam.patch.obj.TableInfo;
import hk.ces.oxfam.patch.result.BaseBeanSQLResult;
import hk.ces.oxfam.patch.result.BeanResult;
import hk.ces.oxfam.patch.result.SQLResult;
import hk.ces.oxfam.patch.result.xml.DataDictXMLFactory;
import hk.ces.oxfam.patch.result.xml.XMLFactory;
import hk.ces.oxfam.patch.sql.QueryUtil;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author ReutyCheng
 */
public class DataDictPatch implements TransactionPatch
{
  public void run(Connection connection) throws SQLException
  {
    XMLFactory<DataDict> factory = new DataDictXMLFactory("DataDict");
    factory.setXMLItems(this.packToDataDict(getTableAndColumn(connection).getBeans()));
    factory.writeToFile();
  }

  private BeanResult<TableAndColumnBean> getTableAndColumn(Connection connection) throws SQLException
  {
    final SQLResult result = QueryUtil.tablesAndColumns(connection, null, Config.SCHEMA.toString(), "%", null);
    BeanResult<TableAndColumnBean> beanResult = new BaseBeanSQLResult<TableAndColumnBean>(result, new BeanPacker<TableAndColumnBean>()
    {
      private final int tableName = result.getColumnIndex("TABLE_NAME", false);
      private final int columnName = result.getColumnIndex("COLUMN_NAME", false);
      private final int typeName = result.getColumnIndex("TYPE_NAME", false);
      private final int columnSize = result.getColumnIndex("COLUMN_SIZE", false);
      
      public TableAndColumnBean pack(Object[] objects)
      {
        TableAndColumnBean bean = new TableAndColumnBean();
        bean.setTableName((String) objects[tableName]);
        bean.setColumnName((String) objects[columnName]);
        bean.setColumnType((String) objects[typeName]);
        bean.setColumnLength((Integer) objects[columnSize]);

        return bean;
      }
    });

    return beanResult;
  }

  private DataDict packToDataDict(List<TableAndColumnBean> beans)
  {
    Map<String, Set<TableAndColumnBean>> map = new LinkedHashMap<String, Set<TableAndColumnBean>>();
    for (TableAndColumnBean bean : beans)
    {
      String tableName = bean.getTableName();
      if (!map.containsKey(tableName))
      {
        map.put(tableName, new LinkedHashSet<TableAndColumnBean>());
      }
      map.get(tableName).add(bean);
    }

    List<TableInfo> tableInfos = new ArrayList<TableInfo>(map.size());
    for (Map.Entry<String, Set<TableAndColumnBean>> entry : map.entrySet())
    {
      TableInfo tableInfo = new TableInfo();
      tableInfo.setTableName(entry.getKey());

      List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(entry.getValue().size());
      for (TableAndColumnBean bean : entry.getValue())
      {
        FieldInfo fieldInfo = new FieldInfo();
        fieldInfo.setColumnName(bean.getColumnName());
        fieldInfo.setTypeName(bean.getColumnType());
        fieldInfo.setSize(bean.getColumnLength() + "");

        fieldInfos.add(fieldInfo);
      }
      tableInfo.setInfoses(fieldInfos);

      tableInfos.add(tableInfo);
    }

    DataDict dataDict = new DataDict();
    dataDict.setTableInfos(tableInfos);
    return dataDict;
  }
}
